package org.jeecg.demo.wx.util;

import org.jeecg.demo.wx.constant.CacheConstant;
import org.jeecg.demo.wx.convert.MapConvert;
import org.jeecg.demo.wx.entity.EScheduleUserCount;
import org.jeecg.demo.wx.enumeration.ScheduleStatusEnum;
import org.jeecg.demo.wx.service.IEScheduleUserCountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能描述
 * 更新计数工具类
 * @author: zgq
 * @date: 2024年03月10日 9:54
 */
@Component
public class UpdateCountUtil {

    @Autowired
    private MyRedisUtil redisUtil;
    @Autowired
    private IEScheduleUserCountService iEScheduleUserCountService;


    public Map<Object, Object> getCountMap(String key) {
        return redisUtil.hmget(key);
    }

    private void setCountMap(String openid, Map<String, Object> map) {
        redisUtil.hmset(CacheConstant.WX_USER_INFO_KEY + openid, map, 3600 * 24);
    }

    public void putCountMap(String openid, Map<String, Object> map) {
        setCountMap(CacheConstant.WX_USER_INFO_KEY + openid, map);
    }

    public void plus(String userID, Map<Object, Object> map, ScheduleStatusEnum... statusEnums) {
        if (Objects.isNull(map)) {
            map = getCountMap(CacheConstant.WX_USER_INFO_KEY + userID);
        }
        for (ScheduleStatusEnum statusEnum : statusEnums) {
            Integer count = (Integer) map.remove(statusEnum.getDesc());
            count++;
            map.put(statusEnum.getDesc(), count);
        }
        Map<String, Object> newMap = MapConvert.convertToStringObjectMap(map);
        putCountMap(userID, newMap);
    }

    public void minus(String userId, ScheduleStatusEnum... statusEnums) {
        Map<Object, Object> map = getCountMap(CacheConstant.WX_USER_INFO_KEY + userId);
        for (ScheduleStatusEnum statusEnum : statusEnums) {
            Integer count = (Integer) map.remove(statusEnum.getDesc());
            count--;
            map.put(statusEnum.getDesc(), count);
        }
        Map<String, Object> newMap = MapConvert.convertToStringObjectMap(map);
        putCountMap(userId, newMap);
    }

    public void update2Db() {
        Set<String> keys = redisUtil.keys(CacheConstant.WX_USER_INFO_KEY);
        if (keys.isEmpty()) {
            return;
        }

        // 获取所有计数信息的 Map
        Map<String, Map<Object, Object>> userCountMap = getUserCountMap(keys);

        // 获取用户 ID 和数据库中对应 ID 的映射关系
        Map<String, String> userIdMap = getUserIdMap(keys);

        // 构建要更新的 EScheduleUserCount 对象列表
        List<EScheduleUserCount> userCountsToUpdate = buildUserCountsToUpdate(userCountMap, userIdMap);

        // 批量更新数据库
        iEScheduleUserCountService.updateBatchById(userCountsToUpdate);
    }

    private Map<String, Map<Object, Object>> getUserCountMap(Set<String> keys) {
        Map<String, Map<Object, Object>> userCountMap = new HashMap<>();
        keys.forEach(key -> {
            String userid = key.substring(CacheConstant.WX_USER_INFO_KEY.length());
            Map<Object, Object> countMap = getCountMap(key);
            userCountMap.put(userid, countMap);
        });
        return userCountMap;
    }

    private Map<String, String> getUserIdMap(Set<String> keys) {
        Set<String> userIdSet = keys.stream()
                .map(key -> key.substring(CacheConstant.WX_USER_INFO_KEY.length()))
                .collect(Collectors.toSet());
        return iEScheduleUserCountService.lambdaQuery()
                .select(EScheduleUserCount::getUserId, EScheduleUserCount::getId)
                .in(EScheduleUserCount::getUserId, userIdSet)
                .list().stream()
                .collect(Collectors.toMap(EScheduleUserCount::getUserId, EScheduleUserCount::getId));
    }

    private List<EScheduleUserCount> buildUserCountsToUpdate(Map<String, Map<Object, Object>> userCountMap,
                                                             Map<String, String> userIdMap) {
        List<EScheduleUserCount> userCountsToUpdate = new ArrayList<>();
        userCountMap.forEach((userId, countMap) -> {
            EScheduleUserCount userCount = convert(countMap);
            userCount.setUserId(userId);
            // 如果存在对应的数据库记录，则设置其 ID
            if (userIdMap.containsKey(userId)) {
                userCount.setId(userIdMap.get(userId));
            }
            userCountsToUpdate.add(userCount);
        });
        return userCountsToUpdate;
    }

    private EScheduleUserCount convert(Map<Object, Object> map) {
        Integer readCount = (Integer) map.getOrDefault(ScheduleStatusEnum.READ.getDesc(), 0);
        Integer unreadCount = (Integer) map.getOrDefault(ScheduleStatusEnum.UNREAD.getDesc(), 0);
        Integer completedCount = (Integer) map.getOrDefault(ScheduleStatusEnum.FINISHED.getDesc(), 0);
        Integer uncompletedCount = (Integer) map.getOrDefault(ScheduleStatusEnum.UNDO.getDesc(), 0);
        return EScheduleUserCount.builder()
                .readCount(readCount).unreadCount(unreadCount)
                .uncompletedCount(completedCount).uncompletedCount(uncompletedCount)
                .build();
    }
}
